package com.dp.mallchat.common.chat.service.strategy.mark;

import com.dp.mallchat.common.chat.dao.MessageDao;
import com.dp.mallchat.common.chat.dao.MessageMarkDao;
import com.dp.mallchat.common.chat.domain.entity.Message;
import com.dp.mallchat.common.chat.domain.entity.MessageMark;
import com.dp.mallchat.common.chat.domain.enums.MessageMarkActTypeEnum;
import com.dp.mallchat.common.chat.domain.enums.MessageMarkTypeEnum;
import com.dp.mallchat.common.common.domain.dto.MsgMarkEventDto;
import com.dp.mallchat.common.common.domain.enums.YesOrNoEnum;
import com.dp.mallchat.common.common.event.MsgMarkEvent;
import com.dp.mallchat.common.common.exception.BusinessException;
import com.dp.mallchat.common.common.utils.AssertUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.Objects;
import java.util.Optional;

/**
 * @Author: dupeng
 * @CreateTime: 2024-07-29  14:31
 * @Description: 消息标记抽象类
 */
@Service
@Slf4j
public abstract class AbstractMarkHandler {

    @Autowired
    private MessageDao messageDao;
    @Autowired
    private MessageMarkDao messageMarkDao;
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @PostConstruct
    private void init(){
        MarkFactory.register(getMsgMarkType().getType(), this);
    }

    protected abstract MessageMarkTypeEnum getMsgMarkType();




    /**
     * 执行动作
     * 场景：
     *      1、未标记过，进行点赞标记/点踩标记
     *      2、标记过，
     *          2.1、点赞，如之前为点赞，则取消点赞，如之前为点踩，取消点踩并增加点赞标记
     *          2.2、点踩，如之前为点赞，则取消点赞并增加点踩标记，如之前为点踩，则取消点踩
     * @param uid
     * @param msgId
     */
    protected void executeAction(Long uid, Long msgId, MessageMarkActTypeEnum markActTypeEnum){
        //消息检查
        Integer msgMarkType = getMsgMarkType().getType();
        Message message = messageDao.getById(msgId);
        AssertUtil.isNotEmpty(message,"消息不存在");

        //点踩记录获取
        MessageMark userMark = messageMarkDao.getUserMark(uid, msgId, msgMarkType);

        if (Objects.isNull(userMark) && markActTypeEnum == MessageMarkActTypeEnum.NO_ACT) {
            return;
        }

        //更新或者新增
        MessageMark insert = MessageMark.builder()
                .id(Optional.ofNullable(userMark).map(MessageMark::getId).orElse(null))
                .msgId(msgId)
                .uid(uid)
                .type(msgMarkType)
                .status(convertStatus(markActTypeEnum))
                .build();
        boolean modify = messageMarkDao.saveOrUpdate(insert);
        //执行成功发送用户事件
        if (modify) {
            applicationEventPublisher.publishEvent(new MsgMarkEvent(this, new MsgMarkEventDto(uid, msgId, msgMarkType, markActTypeEnum.getType())));
        }

    }

    private Integer convertStatus(MessageMarkActTypeEnum markActTypeEnum) {
        if (1 == markActTypeEnum.getType()) {
            return YesOrNoEnum.NO.getStatus();
        }else if (2 == markActTypeEnum.getType()){
            return YesOrNoEnum.YES.getStatus();
        }
        throw new BusinessException("标记类型错误");
    }

    @Transactional
    public void mark(Long uid, Long msgId) {
        doMark(uid, msgId);
    }

    @Transactional
    public void unMark(Long uid, Long msgId) {
        doUnMark(uid, msgId);
    }

    protected void doMark(Long uid, Long msgId) {
        executeAction(uid, msgId, MessageMarkActTypeEnum.ACT);
    }

    protected void doUnMark(Long uid, Long msgId) {
        executeAction(uid, msgId, MessageMarkActTypeEnum.NO_ACT);
    }
}
